home *** CD-ROM | disk | FTP | other *** search
/ The Fatted Calf / The Fatted Calf.iso / Unix / Communication / zmodem / Source / rz.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-10-21  |  31.5 KB  |  1,542 lines

  1. #define VERSION "3.01 5-25-89"
  2. #define PUBDIR "/usr/spool/uucppublic"
  3.  
  4. /*% cc -compat -M2 -Ox -K -i -DMD % -o rz; size rz;
  5. <-xtx-*> cc386 -Ox -DMD rz.c -o $B/rz;  size $B/rz
  6.  *
  7.  * rz.c By Chuck Forsberg
  8.  *
  9.  *    cc -O rz.c -o rz        USG (3.0) Unix
  10.  *     cc -O -DV7  rz.c -o rz        Unix V7, BSD 2.8 - 4.3
  11.  *
  12.  *    ln rz rb;  ln rz rx            For either system
  13.  *
  14.  *    ln rz /usr/bin/rzrmail        For remote mail.  Make this the
  15.  *                    login shell. rzrmail then calls
  16.  *                    rmail(1) to deliver mail.
  17.  *
  18.  * To compile on VMS:
  19.  *
  20.  *    define LNK$LIBRARY   SYS$LIBRARY:VAXCRTL.OLB
  21.  *    cc rz.c
  22.  *    cc vvmodem.c
  23.  *    link rz,vvmodem
  24.  *    rz :== $disk:[username.subdir]rz.exe
  25.  *      For high speed, try increasing the SYSGEN parameter TTY_TYPAHDSZ to 256.
  26.  *
  27.  *
  28.  *  Unix is a trademark of Western Electric Company
  29.  *
  30.  * A program for Unix to receive files and commands from computers running
  31.  *  Professional-YAM, PowerCom, YAM, IMP, or programs supporting XMODEM.
  32.  *  rz uses Unix buffered input to reduce wasted CPU time.
  33.  *
  34.  *    This version implements ZMODEM Run Length Encoding 
  35.  *    and variable length headers.  These features were not funded
  36.  *    by the original Telenet development contract.  This software,
  37.  *    including these features, may be freely used for non
  38.  *    commercial and educational purposes.  This software may also
  39.  *    be freely used to support file transfer operations to or from
  40.  *    licensed Omen Technology products.  Contact Omen Technology
  41.  *    for licensing for other uses.  Any programs which use part or
  42.  *    all of this software must be provided in source form with this
  43.  *    notice intact except by written permission from Omen
  44.  *    Technology Incorporated.
  45.  *
  46.  *        Omen Technology Inc        FAX: 503-621-3745
  47.  *        Post Office Box 4681
  48.  *        Portland OR 97208
  49.  *
  50.  *    Previous versions of this program (not containing the extensions
  51.  *    listed above) remain in the public domain.
  52.  *
  53.  *    This code is made available in the hope it will be useful,
  54.  *    BUT WITHOUT ANY WARRANTY OF ANY KIND OR LIABILITY FOR ANY
  55.  *    DAMAGES OF ANY KIND.
  56.  *
  57.  *
  58.  * Iff the program is invoked by rzCOMMAND, output is piped to 
  59.  * "COMMAND filename"  (Unix only)
  60.  *
  61.  *  Some systems (Venix, Coherent, Regulus) may not support tty raw mode
  62.  *  read(2) the same way as Unix. ONEREAD must be defined to force one
  63.  *  character reads for these systems. Added 7-01-84 CAF
  64.  *
  65.  *  Alarm signal handling changed to work with 4.2 BSD 7-15-84 CAF 
  66.  *
  67.  *  BIX added 6-30-87 to support BIX(TM) upload protocol used by the
  68.  *  Byte Information Exchange.
  69.  *
  70.  *  NFGVMIN Updated 2-18-87 CAF for Xenix systems where c_cc[VMIN]
  71.  *  doesn't work properly (even though it compiles without error!),
  72.  *
  73.  *  SEGMENTS=n added 2-21-88 as a model for CP/M programs
  74.  *    for CP/M-80 systems that cannot overlap modem and disk I/O.
  75.  *
  76.  *  VMS flavor hacks begin with rz version 2.00
  77.  *
  78.  *  -DMD may be added to compiler command line to compile in
  79.  *    Directory-creating routines from Public Domain TAR by John Gilmore
  80.  *
  81.  *  HOWMANY may be tuned for best performance
  82.  *
  83.  *  USG UNIX (3.0) ioctl conventions courtesy  Jeff Martin
  84.  */
  85.  
  86. #ifdef vax11c
  87. #include <types.h>
  88. #include <stat.h>
  89. #define LOGFILE "rzlog.tmp"
  90. #include <stdio.h>
  91. #include <signal.h>
  92. #include <setjmp.h>
  93. #include <ctype.h>
  94. #include <errno.h>
  95. #define OS "VMS"
  96. #define BUFREAD
  97. extern int errno;
  98. #define SS_NORMAL SS$_NORMAL
  99.  
  100. #ifndef PROGNAME
  101. #define PROGNAME "rz"
  102. #endif
  103.  
  104.  
  105. #else
  106.  
  107.  
  108. #define SS_NORMAL 0
  109. #define LOGFILE "/tmp/rzlog"
  110. #include <stdio.h>
  111. #include <signal.h>
  112. #include <setjmp.h>
  113. #include <ctype.h>
  114. #include <errno.h>
  115. extern int errno;
  116. FILE *popen();
  117. #endif
  118.  
  119. #define OK 0
  120. #define FALSE 0
  121. #define TRUE 1
  122. #define ERROR (-1)
  123.  
  124. /*
  125.  * Max value for HOWMANY is 255.
  126.  *   A larger value reduces system overhead but may evoke kernel bugs.
  127.  *   133 corresponds to an XMODEM/CRC sector
  128.  */
  129. #ifndef HOWMANY
  130. #define HOWMANY 133
  131. #endif
  132.  
  133. /* Ward Christensen / CP/M parameters - Don't change these! */
  134. #define ENQ 005
  135. #define CAN ('X'&037)
  136. #define XOFF ('s'&037)
  137. #define XON ('q'&037)
  138. #define SOH 1
  139. #define STX 2
  140. #define EOT 4
  141. #define ACK 6
  142. #define NAK 025
  143. #define CPMEOF 032
  144. #define WANTCRC 0103    /* send C not NAK to get crc not checksum */
  145. #define TIMEOUT (-2)
  146. #define RCDO (-3)
  147. #define GCOUNT (-4)
  148. #define ERRORMAX 5
  149. #define RETRYMAX 5
  150. #define WCEOT (-10)
  151. #define PATHLEN 257    /* ready for 4.2 bsd ? */
  152. #define UNIXFILE 0xF000    /* The S_IFMT file mask bit for stat */
  153.  
  154. int Zmodem=0;        /* ZMODEM protocol requested */
  155. int Nozmodem = 0;    /* If invoked as "rb" */
  156. unsigned Baudrate = 2400;
  157. unsigned Effbaud = 2400;
  158. #ifdef vax11c
  159. #include "vrzsz.c"    /* most of the system dependent stuff here */
  160. #else
  161. #include "rbsb.c"    /* most of the system dependent stuff here */
  162. #endif
  163. #include "crctab.c"
  164.  
  165. char *substr();
  166. FILE *fout;
  167.  
  168. /*
  169.  * Routine to calculate the free bytes on the current file system
  170.  *  ~0 means many free bytes (unknown)
  171.  */
  172. long getfree()
  173. {
  174.     return(~0L);    /* many free bytes ... */
  175. }
  176.  
  177. int Lastrx;
  178. int Crcflg;
  179. int Firstsec;
  180. int Eofseen;        /* indicates cpm eof (^Z) has been received */
  181. int errors;
  182. int Restricted=0;    /* restricted; no /.. or ../ in filenames */
  183. #ifdef ONEREAD
  184. /* Sorry, Regulus and some others don't work right in raw mode! */
  185. int Readnum = 1;    /* Number of bytes to ask for in read() from modem */
  186. #else
  187. int Readnum = HOWMANY;    /* Number of bytes to ask for in read() from modem */
  188. #endif
  189.  
  190. #define DEFBYTL 2000000000L    /* default rx file size */
  191. long Bytesleft;        /* number of bytes of incoming file left */
  192. long Modtime;        /* Unix style mod time for incoming file */
  193. int Filemode;        /* Unix style mode for incoming file */
  194. char Pathname[PATHLEN];
  195. char *Progname;        /* the name by which we were called */
  196.  
  197. int Batch=0;
  198. int Topipe=0;
  199. int MakeLCPathname=TRUE;    /* make received pathname lower case */
  200. int Verbose=0;
  201. int Quiet=0;        /* overrides logic that would otherwise set verbose */
  202. int Nflag = 0;        /* Don't really transfer files */
  203. int Rxclob=FALSE;    /* Clobber existing file */
  204. int Rxbinary=FALSE;    /* receive all files in bin mode */
  205. int Rxascii=FALSE;    /* receive files in ascii (translate) mode */
  206. int Thisbinary;        /* current file is to be received in bin mode */
  207. int Blklen;        /* record length of received packets */
  208.  
  209. #ifdef SEGMENTS
  210. int chinseg = 0;    /* Number of characters received in this data seg */
  211. char secbuf[1+(SEGMENTS+1)*1024];
  212. #else
  213. char secbuf[1025];
  214. #endif
  215.  
  216.  
  217. char linbuf[HOWMANY];
  218. int Lleft=0;        /* number of characters in linbuf */
  219. time_t timep[2];
  220. char Lzmanag;        /* Local file management request */
  221. char zconv;        /* ZMODEM file conversion request */
  222. char zmanag;        /* ZMODEM file management request */
  223. char ztrans;        /* ZMODEM file transport request */
  224. int Zctlesc;        /* Encode control characters */
  225. int Zrwindow = 1400;    /* RX window size (controls garbage count) */
  226.  
  227. jmp_buf tohere;        /* For the interrupt on RX timeout */
  228.  
  229. #define xsendline(c) sendline(c)
  230.  
  231. #include "zm.c"
  232.  
  233. #include "zmr.c"
  234.  
  235. int tryzhdrtype=ZRINIT;    /* Header type to send corresponding to Last rx close */
  236.  
  237. alrm()
  238. {
  239.     longjmp(tohere, -1);
  240. }
  241.  
  242. /* called by signal interrupt or terminate to clean things up */
  243. bibi(n)
  244. {
  245.     if (Zmodem)
  246.         zmputs(Attn);
  247.     canit(); mode(0);
  248.     fprintf(stderr, "rz: caught signal %d; exiting", n);
  249.     cucheck();
  250.     exit(128+n);
  251. }
  252.  
  253. main(argc, argv)
  254. char *argv[];
  255. {
  256.     register char *cp;
  257.     register npats;
  258.     char *virgin, **patts;
  259.     char *getenv();
  260.     int exitcode;
  261.  
  262.     Rxtimeout = 100;
  263.     setbuf(stderr, NULL);
  264.     if ((cp=getenv("SHELL")) && (substr(cp, "rsh") || substr(cp, "rksh")))
  265.         Restricted=TRUE;
  266.  
  267.     from_cu();
  268. #ifdef vax11c
  269.     chkinvok(virgin = PROGNAME);
  270. #else
  271.     chkinvok(virgin=argv[0]);    /* if called as [-]rzCOMMAND set flag */
  272. #endif
  273.     npats = 0;
  274.     while (--argc) {
  275.         cp = *++argv;
  276.         if (*cp == '-') {
  277.             while( *++cp) {
  278.                 switch(*cp) {
  279.                 case '\\':
  280.                      cp[1] = toupper(cp[1]);  continue;
  281.                 case '+':
  282.                     Lzmanag = ZMAPND; break;
  283.                 case 'a':
  284.                     Rxascii=TRUE;  break;
  285.                 case 'b':
  286.                     Rxbinary=TRUE; break;
  287.                 case 'c':
  288.                     Crcflg=TRUE; break;
  289. #ifndef vax11c
  290.                 case 'D':
  291.                     Nflag = TRUE; break;
  292. #endif
  293.                 case 'e':
  294.                     Zctlesc = 1; break;
  295.                 case 'p':
  296.                     Lzmanag = ZMPROT;  break;
  297.                 case 'q':
  298.                     Quiet=TRUE; Verbose=0; break;
  299.                 case 't':
  300.                     if (--argc < 1) {
  301.                         usage();
  302.                     }
  303.                     Rxtimeout = atoi(*++argv);
  304.                     if (Rxtimeout<10 || Rxtimeout>1000)
  305.                         usage();
  306.                     break;
  307.                 case 'w':
  308.                     if (--argc < 1) {
  309.                         usage();
  310.                     }
  311.                     Zrwindow = atoi(*++argv);
  312.                     break;
  313.                 case 'u':
  314.                     MakeLCPathname=FALSE; break;
  315.                 case 'v':
  316.                     ++Verbose; break;
  317.                 case 'y':
  318.                     Rxclob=TRUE; break;
  319.                 default:
  320.                     usage();
  321.                 }
  322.             }
  323.         }
  324.         else if ( !npats && argc>0) {
  325.             if (argv[0][0]) {
  326.                 npats=argc;
  327.                 patts=argv;
  328.             }
  329.         }
  330.     }
  331.     if (npats > 1)
  332.         usage();
  333.     if (Batch && npats)
  334.         usage();
  335.     if (Verbose) {
  336.         if (freopen(LOGFILE, "a", stderr)==NULL) {
  337.             printf("Can't open log file %s\n",LOGFILE);
  338.             exit(0200);
  339.         }
  340.         setbuf(stderr, NULL);
  341.         fprintf(stderr, "argv[0]=%s Progname=%s\n", virgin, Progname);
  342.     }
  343.     if (Fromcu && !Quiet) {
  344.         if (Verbose == 0)
  345.             Verbose = 2;
  346.     }
  347.     vfile("%s %s for %s\n", Progname, VERSION, OS);
  348.     mode(1);
  349.     if (signal(SIGINT, bibi) == SIG_IGN) {
  350.         signal(SIGINT, SIG_IGN); signal(SIGKILL, SIG_IGN);
  351.     }
  352.     else {
  353.         signal(SIGINT, bibi); signal(SIGKILL, bibi);
  354.     }
  355.     signal(SIGTERM, bibi);
  356.     if (wcreceive(npats, patts)==ERROR) {
  357.         exitcode=0200;
  358.         canit();
  359.     }
  360.     mode(0);
  361.     if (exitcode && !Zmodem)    /* bellow again with all thy might. */
  362.         canit();
  363.     if (exitcode)
  364.         cucheck();
  365.     exit(exitcode ? exitcode:SS_NORMAL);
  366. }
  367.  
  368.  
  369. usage()
  370. {
  371.     cucheck();
  372.     fprintf(stderr,"Usage:    rz [-abeuvy]        (ZMODEM)\n");
  373.     fprintf(stderr,"or    rb [-abuvy]        (YMODEM)\n");
  374.     fprintf(stderr,"or    rx [-abcv] file    (XMODEM or XMODEM-1k)\n");
  375.     fprintf(stderr,"      -a ASCII transfer (strip CR)\n");
  376.     fprintf(stderr,"      -b Binary transfer for all files\n");
  377. #ifndef vax11c
  378.     fprintf(stderr,"      -c Use 16 bit CRC    (XMODEM)\n");
  379. #endif
  380.     fprintf(stderr,"      -e Escape control characters    (ZMODEM)\n");
  381.     fprintf(stderr,"      -v Verbose more v's give more info\n");
  382.     fprintf(stderr,"      -y Yes, clobber existing file if any\n");
  383.     fprintf(stderr,"%s %s for %s by Chuck Forsberg, Omen Technology INC\n",
  384.       Progname, VERSION, OS);
  385.     fprintf(stderr, "\t\t\042The High Reliability Software\042\n");
  386.     exit(SS_NORMAL);
  387. }
  388. /*
  389.  *  Debugging information output interface routine
  390.  */
  391. /* VARARGS1 */
  392. vfile(f, a, b, c)
  393. register char *f;
  394. {
  395.     if (Verbose > 2) {
  396.         fprintf(stderr, f, a, b, c);
  397.         fprintf(stderr, "\n");
  398.     }
  399. }
  400.  
  401. /*
  402.  * Let's receive something already.
  403.  */
  404.  
  405. char *rbmsg =
  406. "%s ready. To begin transfer, type \"%s file ...\" to your modem program\r\n\n";
  407.  
  408. wcreceive(argc, argp)
  409. char **argp;
  410. {
  411.     register c;
  412.  
  413.     if (Batch || argc==0) {
  414.         Crcflg=1;
  415.         if ( !Quiet)
  416.             fprintf(stderr, rbmsg, Progname, Nozmodem?"sb":"sz");
  417.         if (c=tryz()) {
  418.             if (c == ZCOMPL)
  419.                 return OK;
  420.             if (c == ERROR)
  421.                 goto fubar;
  422.             c = rzfiles();
  423.             if (c)
  424.                 goto fubar;
  425.         } else {
  426.             for (;;) {
  427.                 if (wcrxpn(secbuf)== ERROR)
  428.                     goto fubar;
  429.                 if (secbuf[0]==0)
  430.                     return OK;
  431.                 if (procheader(secbuf) == ERROR)
  432.                     goto fubar;
  433.                 if (wcrx()==ERROR)
  434.                     goto fubar;
  435.             }
  436.         }
  437.     } else {
  438.         Bytesleft = DEFBYTL; Filemode = 0; Modtime = 0L;
  439.  
  440.         procheader(""); strcpy(Pathname, *argp); checkpath(Pathname);
  441.         fprintf(stderr, "\nrz: ready to receive %s\r\n", Pathname);
  442.         if ((fout=fopen(Pathname, "w")) == NULL)
  443.             return ERROR;
  444.         if (wcrx()==ERROR)
  445.             goto fubar;
  446.     }
  447.     return OK;
  448. fubar:
  449.     canit();
  450. #ifndef vax11c
  451.     if (Topipe && fout) {
  452.         pclose(fout);  return ERROR;
  453.     }
  454. #endif
  455.     Modtime = 1;
  456.     if (fout)
  457.         fclose(fout);
  458. #ifndef vax11c
  459.     if (Restricted) {
  460.         unlink(Pathname);
  461.         fprintf(stderr, "\r\nrz: %s removed.\r\n", Pathname);
  462.     }
  463. #endif
  464.     return ERROR;
  465. }
  466.  
  467.  
  468. /*
  469.  * Fetch a pathname from the other end as a C ctyle ASCIZ string.
  470.  * Length is indeterminate as long as less than Blklen
  471.  * A null string represents no more files (YMODEM)
  472.  */
  473. wcrxpn(rpn)
  474. char *rpn;    /* receive a pathname */
  475. {
  476.     register c;
  477.  
  478. #ifdef NFGVMIN
  479.     readline(1);
  480. #else
  481.     purgeline();
  482. #endif
  483.  
  484. et_tu:
  485.     Firstsec=TRUE;  Eofseen=FALSE;
  486.     sendline(Crcflg?WANTCRC:NAK);
  487.     Lleft=0;    /* Do read next time ... */
  488.     while ((c = wcgetsec(rpn, 100)) != 0) {
  489.         if (c == WCEOT) {
  490.             zperr( "Pathname fetch returned %d", c);
  491.             sendline(ACK);
  492.             Lleft=0;    /* Do read next time ... */
  493.             readline(1);
  494.             goto et_tu;
  495.         }
  496.         return ERROR;
  497.     }
  498.     sendline(ACK);
  499.     return OK;
  500. }
  501.  
  502. /*
  503.  * Adapted from CMODEM13.C, written by
  504.  * Jack M. Wierda and Roderick W. Hart
  505.  */
  506.  
  507. wcrx()
  508. {
  509.     register int sectnum, sectcurr;
  510.     register char sendchar;
  511.     register char *p;
  512.     int cblklen;            /* bytes to dump this block */
  513.  
  514.     Firstsec=TRUE;sectnum=0; Eofseen=FALSE;
  515.     sendchar=Crcflg?WANTCRC:NAK;
  516.  
  517.     for (;;) {
  518.         sendline(sendchar);    /* send it now, we're ready! */
  519.         Lleft=0;    /* Do read next time ... */
  520.         sectcurr=wcgetsec(secbuf, (sectnum&0177)?50:130);
  521.         report(sectcurr);
  522.         if (sectcurr==(sectnum+1 &0377)) {
  523.             sectnum++;
  524.             cblklen = Bytesleft>Blklen ? Blklen:Bytesleft;
  525.             if (putsec(secbuf, cblklen)==ERROR)
  526.                 return ERROR;
  527.             if ((Bytesleft-=cblklen) < 0)
  528.                 Bytesleft = 0;
  529.             sendchar=ACK;
  530.         }
  531.         else if (sectcurr==(sectnum&0377)) {
  532.             zperr( "Received dup Sector");
  533.             sendchar=ACK;
  534.         }
  535.         else if (sectcurr==WCEOT) {
  536.             if (closeit())
  537.                 return ERROR;
  538.             sendline(ACK);
  539.             Lleft=0;    /* Do read next time ... */
  540.             return OK;
  541.         }
  542.         else if (sectcurr==ERROR)
  543.             return ERROR;
  544.         else {
  545.             zperr( "Sync Error");
  546.             return ERROR;
  547.         }
  548.     }
  549. }
  550.  
  551. /*
  552.  * Wcgetsec fetches a Ward Christensen type sector.
  553.  * Returns sector number encountered or ERROR if valid sector not received,
  554.  * or CAN CAN received
  555.  * or WCEOT if eot sector
  556.  * time is timeout for first char, set to 4 seconds thereafter
  557.  ***************** NO ACK IS SENT IF SECTOR IS RECEIVED OK **************
  558.  *    (Caller must do that when he is good and ready to get next sector)
  559.  */
  560.  
  561. wcgetsec(rxbuf, maxtime)
  562. char *rxbuf;
  563. int maxtime;
  564. {
  565.     register checksum, wcj, firstch;
  566.     register unsigned short oldcrc;
  567.     register char *p;
  568.     int sectcurr;
  569.  
  570.     for (Lastrx=errors=0; errors<RETRYMAX; errors++) {
  571.  
  572.         if ((firstch=readline(maxtime))==STX) {
  573.             Blklen=1024; goto get2;
  574.         }
  575.         if (firstch==SOH) {
  576.             Blklen=128;
  577. get2:
  578.             sectcurr=readline(1);
  579.             if ((sectcurr+(oldcrc=readline(1)))==0377) {
  580.                 oldcrc=checksum=0;
  581.                 for (p=rxbuf,wcj=Blklen; --wcj>=0; ) {
  582.                     if ((firstch=readline(1)) < 0)
  583.                         goto bilge;
  584.                     oldcrc=updcrc(firstch, oldcrc);
  585.                     checksum += (*p++ = firstch);
  586.                 }
  587.                 if ((firstch=readline(1)) < 0)
  588.                     goto bilge;
  589.                 if (Crcflg) {
  590.                     oldcrc=updcrc(firstch, oldcrc);
  591.                     if ((firstch=readline(1)) < 0)
  592.                         goto bilge;
  593.                     oldcrc=updcrc(firstch, oldcrc);
  594.                     if (oldcrc & 0xFFFF)
  595.                         zperr( "CRC");
  596.                     else {
  597.                         Firstsec=FALSE;
  598.                         return sectcurr;
  599.                     }
  600.                 }
  601.                 else if (((checksum-firstch)&0377)==0) {
  602.                     Firstsec=FALSE;
  603.                     return sectcurr;
  604.                 }
  605.                 else
  606.                     zperr( "Checksum");
  607.             }
  608.             else
  609.                 zperr("Sector number garbled");
  610.         }
  611.         /* make sure eot really is eot and not just mixmash */
  612. #ifdef NFGVMIN
  613.         else if (firstch==EOT && readline(1)==TIMEOUT)
  614.             return WCEOT;
  615. #else
  616.         else if (firstch==EOT && Lleft==0)
  617.             return WCEOT;
  618. #endif
  619.         else if (firstch==CAN) {
  620.             if (Lastrx==CAN) {
  621.                 zperr( "Sender CANcelled");
  622.                 return ERROR;
  623.             } else {
  624.                 Lastrx=CAN;
  625.                 continue;
  626.             }
  627.         }
  628.         else if (firstch==TIMEOUT) {
  629.             if (Firstsec)
  630.                 goto humbug;
  631. bilge:
  632.             zperr( "TIMEOUT");
  633.         }
  634.         else
  635.             zperr( "Got 0%o sector header", firstch);
  636.  
  637. humbug:
  638.         Lastrx=0;
  639.         while(readline(1)!=TIMEOUT)
  640.             ;
  641.         if (Firstsec) {
  642.             sendline(Crcflg?WANTCRC:NAK);
  643.             Lleft=0;    /* Do read next time ... */
  644.         } else {
  645.             maxtime=40; sendline(NAK);
  646.             Lleft=0;    /* Do read next time ... */
  647.         }
  648.     }
  649.     /* try to stop the bubble machine. */
  650.     canit();
  651.     return ERROR;
  652. }
  653.  
  654. #ifndef vax11c
  655. /*
  656.  * This version of readline is reasoably well suited for
  657.  * reading many characters.
  658.  *  (except, currently, for the Regulus version!)
  659.  *
  660.  * timeout is in tenths of seconds
  661.  */
  662. readline(timeout)
  663. int timeout;
  664. {
  665.     register n;
  666.     static char *cdq;    /* pointer for removing chars from linbuf */
  667.  
  668.     if (--Lleft >= 0) {
  669.         if (Verbose > 8) {
  670.             fprintf(stderr, "%02x ", *cdq&0377);
  671.         }
  672.         return (*cdq++ & 0377);
  673.     }
  674.     n = timeout/10;
  675.     if (n < 2)
  676.         n = 3;
  677.     if (Verbose > 5)
  678.         fprintf(stderr, "Calling read: alarm=%d  Readnum=%d ",
  679.           n, Readnum);
  680.     if (setjmp(tohere)) {
  681. #ifdef TIOCFLUSH
  682. /*        ioctl(0, TIOCFLUSH, 0); */
  683. #endif
  684.         Lleft = 0;
  685.         if (Verbose>1)
  686.             fprintf(stderr, "Readline:TIMEOUT\n");
  687.         return TIMEOUT;
  688.     }
  689.     signal(SIGALRM, alrm); alarm(n);
  690.     Lleft=read(0, cdq=linbuf, Readnum);
  691.     alarm(0);
  692.     if (Verbose > 5) {
  693.         fprintf(stderr, "Read returned %d bytes\n", Lleft);
  694.     }
  695.     if (Lleft < 1)
  696.         return TIMEOUT;
  697.     --Lleft;
  698.     if (Verbose > 8) {
  699.         fprintf(stderr, "%02x ", *cdq&0377);
  700.     }
  701.     return (*cdq++ & 0377);
  702. }
  703.  
  704.  
  705.  
  706. /*
  707.  * Purge the modem input queue of all characters
  708.  */
  709. purgeline()
  710. {
  711.     Lleft = 0;
  712. #ifdef USG
  713.     ioctl(0, TCFLSH, 0);
  714. #else
  715.     lseek(0, 0L, 2);
  716. #endif
  717. }
  718. #endif
  719.  
  720.  
  721. /*
  722.  * Process incoming file information header
  723.  */
  724. procheader(name)
  725. char *name;
  726. {
  727.     register char *openmode, *p, **pp;
  728.  
  729.     /* set default parameters and overrides */
  730.     openmode = "w";
  731.     Thisbinary = (!Rxascii) || Rxbinary;
  732.     if (Lzmanag)
  733.         zmanag = Lzmanag;
  734.  
  735.     /*
  736.      *  Process ZMODEM remote file management requests
  737.      */
  738.     if (!Rxbinary && zconv == ZCNL)    /* Remote ASCII override */
  739.         Thisbinary = 0;
  740.     if (zconv == ZCBIN)    /* Remote Binary override */
  741.         Thisbinary = TRUE;
  742.     else if (zmanag == ZMAPND)
  743.         openmode = "a";
  744.  
  745. #ifndef BIX
  746.     /* Check for existing file */
  747.     if (!Rxclob && (zmanag&ZMMASK) != ZMCLOB && (fout=fopen(name, "r"))) {
  748.         fclose(fout);  return ERROR;
  749.     }
  750. #endif
  751.  
  752.     Bytesleft = DEFBYTL; Filemode = 0; Modtime = 0L;
  753.  
  754.     p = name + 1 + strlen(name);
  755.     if (*p) {    /* file coming from Unix or DOS system */
  756.         sscanf(p, "%ld%lo%o", &Bytesleft, &Modtime, &Filemode);
  757. #ifndef vax11c
  758.         if (Filemode & UNIXFILE)
  759.             ++Thisbinary;
  760. #endif
  761.         if (Verbose) {
  762.             fprintf(stderr,  "Incoming: %s %ld %lo %o\n",
  763.               name, Bytesleft, Modtime, Filemode);
  764.         }
  765.     }
  766.  
  767. #ifdef BIX
  768.     if ((fout=fopen("scratchpad", openmode)) == NULL)
  769.         return ERROR;
  770.     return OK;
  771. #else
  772.  
  773.     else {        /* File coming from CP/M system */
  774.         for (p=name; *p; ++p)        /* change / to _ */
  775.             if ( *p == '/')
  776.                 *p = '_';
  777.  
  778.         if ( *--p == '.')        /* zap trailing period */
  779.             *p = 0;
  780.     }
  781.  
  782. #ifndef vax11c
  783.     if (!Zmodem && MakeLCPathname && !IsAnyLower(name)
  784.       && !(Filemode&UNIXFILE))
  785.         uncaps(name);
  786. #endif
  787.     if (Topipe > 0) {
  788.         sprintf(Pathname, "%s %s", Progname+2, name);
  789.         if (Verbose)
  790.             fprintf(stderr,  "Topipe: %s %s\n",
  791.               Pathname, Thisbinary?"BIN":"ASCII");
  792. #ifndef vax11c
  793.         if ((fout=popen(Pathname, "w")) == NULL)
  794.             return ERROR;
  795. #endif
  796.     } else {
  797.         strcpy(Pathname, name);
  798.         if (Verbose) {
  799.             fprintf(stderr,  "Receiving %s %s %s\n",
  800.               name, Thisbinary?"BIN":"ASCII", openmode);
  801.         }
  802.         checkpath(name);
  803.         if (Nflag)
  804.             name = "/dev/null";
  805. #ifndef vax11c
  806.         if (name[0] == '!' || name[0] == '|') {
  807.             if ( !(fout = popen(name+1, "w"))) {
  808.                 return ERROR;
  809.             }
  810.             Topipe = -1;  return(OK);
  811.         }
  812. #endif
  813. #ifdef MD
  814.         fout = fopen(name, openmode);
  815.         if ( !fout)
  816.             if (make_dirs(name))
  817.                 fout = fopen(name, openmode);
  818. #else
  819.         fout = fopen(name, openmode);
  820. #endif
  821.         if ( !fout)
  822.             return ERROR;
  823.     }
  824.     return OK;
  825. #endif /* BIX */
  826. }
  827.  
  828. #ifdef MD
  829. /*
  830.  *  Directory-creating routines from Public Domain TAR by John Gilmore
  831.  */
  832.  
  833. /*
  834.  * After a file/link/symlink/dir creation has failed, see if
  835.  * it's because some required directory was not present, and if
  836.  * so, create all required dirs.
  837.  */
  838. make_dirs(pathname)
  839. register char *pathname;
  840. {
  841.     register char *p;        /* Points into path */
  842.     int madeone = 0;        /* Did we do anything yet? */
  843.     int save_errno = errno;        /* Remember caller's errno */
  844.  
  845.     if (errno != ENOENT)
  846.         return 0;        /* Not our problem */
  847.  
  848.     for (p = strchr(pathname, '/'); p != NULL; p = strchr(p+1, '/')) {
  849.         /* Avoid mkdir of empty string, if leading or double '/' */
  850.         if (p == pathname || p[-1] == '/')
  851.             continue;
  852.         /* Avoid mkdir where last part of path is '.' */
  853.         if (p[-1] == '.' && (p == pathname+1 || p[-2] == '/'))
  854.             continue;
  855.         *p = 0;                /* Truncate the path there */
  856.         if ( !mkdir(pathname, 0777)) {    /* Try to create it as a dir */
  857.             vfile("Made directory %s\n", pathname);
  858.             madeone++;        /* Remember if we made one */
  859.             *p = '/';
  860.             continue;
  861.         }
  862.         *p = '/';
  863.         if (errno == EEXIST)        /* Directory already exists */
  864.             continue;
  865.         /*
  866.          * Some other error in the mkdir.  We return to the caller.
  867.          */
  868.         break;
  869.     }
  870.     errno = save_errno;        /* Restore caller's errno */
  871.     return madeone;            /* Tell them to retry if we made one */
  872. }
  873.  
  874. #if (MD != 2)
  875. #define    TERM_SIGNAL(status)    ((status) & 0x7F)
  876. #define TERM_COREDUMP(status)    (((status) & 0x80) != 0)
  877. #define TERM_VALUE(status)    ((status) >> 8)
  878. /*
  879.  * Make a directory.  Compatible with the mkdir() system call on 4.2BSD.
  880.  */
  881. mkdir(dpath, dmode)
  882. char *dpath;
  883. int dmode;
  884. {
  885.     int cpid, status;
  886.     struct stat statbuf;
  887.  
  888.     if (stat(dpath,&statbuf) == 0) {
  889.         errno = EEXIST;        /* Stat worked, so it already exists */
  890.         return -1;
  891.     }
  892.  
  893.     /* If stat fails for a reason other than non-existence, return error */
  894.     if (errno != ENOENT) return -1; 
  895.  
  896.     switch (cpid = fork()) {
  897.  
  898.     case -1:            /* Error in fork() */
  899.         return(-1);        /* Errno is set already */
  900.  
  901.     case 0:                /* Child process */
  902.         /*
  903.          * Cheap hack to set mode of new directory.  Since this
  904.          * child process is going away anyway, we zap its umask.
  905.          * FIXME, this won't suffice to set SUID, SGID, etc. on this
  906.          * directory.  Does anybody care?
  907.          */
  908.         status = umask(0);    /* Get current umask */
  909.         status = umask(status | (0777 & ~dmode)); /* Set for mkdir */
  910.         execl("/bin/mkdir", "mkdir", dpath, (char *)0);
  911.         _exit(-1);        /* Can't exec /bin/mkdir */
  912.     
  913.     default:            /* Parent process */
  914.         while (cpid != wait(&status)) ;    /* Wait for kid to finish */
  915.     }
  916.  
  917.     if (TERM_SIGNAL(status) != 0 || TERM_VALUE(status) != 0) {
  918.         errno = EIO;        /* We don't know why, but */
  919.         return -1;        /* /bin/mkdir failed */
  920.     }
  921.  
  922.     return 0;
  923. }
  924. #endif /* MD != 2 */
  925. #endif /* MD */
  926.  
  927. /*
  928.  * Putsec writes the n characters of buf to receive file fout.
  929.  *  If not in binary mode, carriage returns, and all characters
  930.  *  starting with CPMEOF are discarded.
  931.  */
  932. putsec(buf, n)
  933. char *buf;
  934. register n;
  935. {
  936.     register char *p;
  937.  
  938.     if (n == 0)
  939.         return OK;
  940.     if (Thisbinary) {
  941.         for (p=buf; --n>=0; )
  942.             putc( *p++, fout);
  943.     }
  944.     else {
  945.         if (Eofseen)
  946.             return OK;
  947.         for (p=buf; --n>=0; ++p ) {
  948.             if ( *p == '\r')
  949.                 continue;
  950.             if (*p == CPMEOF) {
  951.                 Eofseen=TRUE; return OK;
  952.             }
  953.             putc(*p ,fout);
  954.         }
  955.     }
  956.     return OK;
  957. }
  958.  
  959. #ifndef vax11c
  960. /*
  961.  *  Send a character to modem.  Small is beautiful.
  962.  */
  963. sendline(c)
  964. {
  965.     char d;
  966.  
  967.     d = c;
  968.     if (Verbose>6)
  969.         fprintf(stderr, "Sendline: %x\n", c);
  970.     write(1, &d, 1);
  971. }
  972.  
  973. flushmo() {}
  974. #endif
  975.  
  976.  
  977.  
  978.  
  979.  
  980. /* make string s lower case */
  981. uncaps(s)
  982. register char *s;
  983. {
  984.     for ( ; *s; ++s)
  985.         if (isupper(*s))
  986.             *s = tolower(*s);
  987. }
  988. /*
  989.  * IsAnyLower returns TRUE if string s has lower case letters.
  990.  */
  991. IsAnyLower(s)
  992. register char *s;
  993. {
  994.     for ( ; *s; ++s)
  995.         if (islower(*s))
  996.             return TRUE;
  997.     return FALSE;
  998. }
  999.  
  1000. /*
  1001.  * substr(string, token) searches for token in string s
  1002.  * returns pointer to token within string if found, NULL otherwise
  1003.  */
  1004. char *
  1005. substr(s, t)
  1006. register char *s,*t;
  1007. {
  1008.     register char *ss,*tt;
  1009.     /* search for first char of token */
  1010.     for (ss=s; *s; s++)
  1011.         if (*s == *t)
  1012.             /* compare token with substring */
  1013.             for (ss=s,tt=t; ;) {
  1014.                 if (*tt == 0)
  1015.                     return s;
  1016.                 if (*ss++ != *tt++)
  1017.                     break;
  1018.             }
  1019.     return NULL;
  1020. }
  1021.  
  1022. /*
  1023.  * Log an error
  1024.  */
  1025. /*VARARGS1*/
  1026. zperr(s,p,u)
  1027. char *s, *p, *u;
  1028. {
  1029.     if (Verbose <= 0)
  1030.         return;
  1031.     fprintf(stderr, "Retry %d: ", errors);
  1032.     fprintf(stderr, s, p, u);
  1033.     fprintf(stderr, "\n");
  1034. }
  1035.  
  1036. /* send cancel string to get the other end to shut up */
  1037. canit()
  1038. {
  1039.     static char canistr[] = {
  1040.      24,24,24,24,24,24,24,24,24,24,8,8,8,8,8,8,8,8,8,8,0
  1041.     };
  1042.  
  1043. #ifdef vax11c
  1044.     raw_wbuf(strlen(canistr), canistr);
  1045.     purgeline();
  1046. #else
  1047.     printf(canistr);
  1048.     Lleft=0;    /* Do read next time ... */
  1049.     fflush(stdout);
  1050. #endif
  1051. }
  1052.  
  1053.  
  1054. report(sct)
  1055. int sct;
  1056. {
  1057.     if (Verbose>1)
  1058.         fprintf(stderr,"%03d%c",sct,sct%10? ' ' : '\r');
  1059. }
  1060.  
  1061. /*
  1062.  * If called as [-][dir/../]vrzCOMMAND set Verbose to 1
  1063.  * If called as [-][dir/../]rzCOMMAND set the pipe flag
  1064.  * If called as rb use YMODEM protocol
  1065.  */
  1066. chkinvok(s)
  1067. char *s;
  1068. {
  1069.     register char *p;
  1070.  
  1071.     p = s;
  1072.     while (*p == '-')
  1073.         s = ++p;
  1074.     while (*p)
  1075.         if (*p++ == '/')
  1076.             s = p;
  1077.     if (*s == 'v') {
  1078.         Verbose=1; ++s;
  1079.     }
  1080.     Progname = s;
  1081.     if (s[0]=='r' && s[1]=='z')
  1082.         Batch = TRUE;
  1083.     if (s[0]=='r' && s[1]=='b')
  1084.         Batch = Nozmodem = TRUE;
  1085.     if (s[2] && s[0]=='r' && s[1]=='b')
  1086.         Topipe = 1;
  1087.     if (s[2] && s[0]=='r' && s[1]=='z')
  1088.         Topipe = 1;
  1089. }
  1090.  
  1091. /*
  1092.  * Totalitarian Communist pathname processing
  1093.  */
  1094. checkpath(name)
  1095. char *name;
  1096. {
  1097.     if (Restricted) {
  1098.         if (fopen(name, "r") != NULL) {
  1099.             canit();
  1100.             fprintf(stderr, "\r\nrz: %s exists\n", name);
  1101.             bibi(-1);
  1102.         }
  1103.         /* restrict pathnames to current tree or uucppublic */
  1104.         if ( substr(name, "../")
  1105.          || (name[0]== '/' && strncmp(name, PUBDIR, strlen(PUBDIR))) ) {
  1106.             canit();
  1107.             fprintf(stderr,"\r\nrz:\tSecurity Violation\r\n");
  1108.             bibi(-1);
  1109.         }
  1110.     }
  1111. }
  1112.  
  1113. /*
  1114.  * Initialize for Zmodem receive attempt, try to activate Zmodem sender
  1115.  *  Handles ZSINIT frame
  1116.  *  Return ZFILE if Zmodem filename received, -1 on error,
  1117.  *   ZCOMPL if transaction finished,  else 0
  1118.  */
  1119. tryz()
  1120. {
  1121.     register c, n;
  1122.     register cmdzack1flg;
  1123.  
  1124.     if (Nozmodem)        /* Check for "rb" program name */
  1125.         return 0;
  1126.  
  1127.  
  1128.     for (n=Zmodem?15:5; --n>=0; ) {
  1129.         /* Set buffer length (0) and capability flags */
  1130. #ifdef SEGMENTS
  1131.         stohdr(SEGMENTS*1024L);
  1132. #else
  1133.         stohdr(0L);
  1134. #endif
  1135. #ifdef CANBREAK
  1136.         Txhdr[ZF0] = CANFC32|CANFDX|CANOVIO|CANBRK;
  1137. #else
  1138.         Txhdr[ZF0] = CANFC32|CANFDX|CANOVIO;
  1139. #endif
  1140.         if (Zctlesc)
  1141.             Txhdr[ZF0] |= TESCCTL;
  1142.         Txhdr[ZF0] |= CANRLE;
  1143.         Txhdr[ZF1] = CANVHDR;
  1144.         /* tryzhdrtype may == ZRINIT */
  1145.         zshhdr(4,tryzhdrtype, Txhdr);
  1146.         if (tryzhdrtype == ZSKIP)    /* Don't skip too far */
  1147.             tryzhdrtype = ZRINIT;    /* CAF 8-21-87 */
  1148. again:
  1149.         switch (zgethdr(Rxhdr, 0)) {
  1150.         case ZRQINIT:
  1151.             if (Rxhdr[ZF3] & 0x80)
  1152.                 Usevhdrs = 1;    /* we can var header */
  1153.             continue;
  1154.         case ZEOF:
  1155.             continue;
  1156.         case TIMEOUT:
  1157.             continue;
  1158.         case ZFILE:
  1159.             zconv = Rxhdr[ZF0];
  1160.             zmanag = Rxhdr[ZF1];
  1161.             ztrans = Rxhdr[ZF2];
  1162.             if (Rxhdr[ZF3] & ZCANVHDR)
  1163.                 Usevhdrs = TRUE;
  1164.             tryzhdrtype = ZRINIT;
  1165.             c = zrdata(secbuf, 1024);
  1166.             mode(3);
  1167.             if (c == GOTCRCW)
  1168.                 return ZFILE;
  1169.             zshhdr(4,ZNAK, Txhdr);
  1170.             goto again;
  1171.         case ZSINIT:
  1172.             Zctlesc = TESCCTL & Rxhdr[ZF0];
  1173.             if (zrdata(Attn, ZATTNLEN) == GOTCRCW) {
  1174.                 stohdr(1L);
  1175.                 zshhdr(4,ZACK, Txhdr);
  1176.                 goto again;
  1177.             }
  1178.             zshhdr(4,ZNAK, Txhdr);
  1179.             goto again;
  1180.         case ZFREECNT:
  1181.             stohdr(getfree());
  1182.             zshhdr(4,ZACK, Txhdr);
  1183.             goto again;
  1184.         case ZCOMMAND:
  1185. #ifdef vax11c
  1186.             return ERROR;
  1187. #else
  1188.             cmdzack1flg = Rxhdr[ZF0];
  1189.             if (zrdata(secbuf, 1024) == GOTCRCW) {
  1190.                 if (cmdzack1flg & ZCACK1)
  1191.                     stohdr(0L);
  1192.                 else
  1193.                     stohdr((long)sys2(secbuf));
  1194.                 purgeline();    /* dump impatient questions */
  1195.                 do {
  1196.                     zshhdr(4,ZCOMPL, Txhdr);
  1197.                 }
  1198.                 while (++errors<20 && zgethdr(Rxhdr,1) != ZFIN);
  1199.                 ackbibi();
  1200.                 if (cmdzack1flg & ZCACK1)
  1201.                     exec2(secbuf);
  1202.                 return ZCOMPL;
  1203.             }
  1204.             zshhdr(4,ZNAK, Txhdr); goto again;
  1205. #endif
  1206.         case ZCOMPL:
  1207.             goto again;
  1208.         default:
  1209.             continue;
  1210.         case ZFIN:
  1211.             ackbibi(); return ZCOMPL;
  1212.         case ZCAN:
  1213.             return ERROR;
  1214.         }
  1215.     }
  1216.     return 0;
  1217. }
  1218.  
  1219. /*
  1220.  * Receive 1 or more files with ZMODEM protocol
  1221.  */
  1222. rzfiles()
  1223. {
  1224.     register c;
  1225.  
  1226.     for (;;) {
  1227.         switch (c = rzfile()) {
  1228.         case ZEOF:
  1229.         case ZSKIP:
  1230.             switch (tryz()) {
  1231.             case ZCOMPL:
  1232.                 return OK;
  1233.             default:
  1234.                 return ERROR;
  1235.             case ZFILE:
  1236.                 break;
  1237.             }
  1238.             continue;
  1239.         default:
  1240.             return c;
  1241.         case ERROR:
  1242.             return ERROR;
  1243.         }
  1244.     }
  1245. }
  1246.  
  1247. /*
  1248.  * Receive a file with ZMODEM protocol
  1249.  *  Assumes file name frame is in secbuf
  1250.  */
  1251. rzfile()
  1252. {
  1253.     register c, n;
  1254.     long rxbytes;
  1255.  
  1256.     Eofseen=FALSE;
  1257.     if (procheader(secbuf) == ERROR) {
  1258.         return (tryzhdrtype = ZSKIP);
  1259.     }
  1260.  
  1261.     n = 20; rxbytes = 0l;
  1262.  
  1263.     for (;;) {
  1264. #ifdef SEGMENTS
  1265.         chinseg = 0;
  1266. #endif
  1267.         stohdr(rxbytes);
  1268.         zshhdr(4,ZRPOS, Txhdr);
  1269. nxthdr:
  1270.         switch (c = zgethdr(Rxhdr, 0)) {
  1271.         default:
  1272.             vfile("rzfile: zgethdr returned %d", c);
  1273.             return ERROR;
  1274.         case ZNAK:
  1275.         case TIMEOUT:
  1276. #ifdef SEGMENTS
  1277.             putsec(secbuf, chinseg);
  1278.             chinseg = 0;
  1279. #endif
  1280.             if ( --n < 0) {
  1281.                 vfile("rzfile: zgethdr returned %d", c);
  1282.                 return ERROR;
  1283.             }
  1284.         case ZFILE:
  1285.             zrdata(secbuf, 1024);
  1286.             continue;
  1287.         case ZEOF:
  1288. #ifdef SEGMENTS
  1289.             putsec(secbuf, chinseg);
  1290.             chinseg = 0;
  1291. #endif
  1292.             if (rclhdr(Rxhdr) != rxbytes) {
  1293.                 /*
  1294.                  * Ignore eof if it's at wrong place - force
  1295.                  *  a timeout because the eof might have gone
  1296.                  *  out before we sent our zrpos.
  1297.                  */
  1298.                 errors = 0;  goto nxthdr;
  1299.             }
  1300.             if (closeit()) {
  1301.                 tryzhdrtype = ZFERR;
  1302.                 vfile("rzfile: closeit returned <> 0");
  1303.                 return ERROR;
  1304.             }
  1305.             vfile("rzfile: normal EOF");
  1306.             return c;
  1307.         case ERROR:    /* Too much garbage in header search error */
  1308. #ifdef SEGMENTS
  1309.             putsec(secbuf, chinseg);
  1310.             chinseg = 0;
  1311. #endif
  1312.             if ( --n < 0) {
  1313.                 vfile("rzfile: zgethdr returned %d", c);
  1314.                 return ERROR;
  1315.             }
  1316.             zmputs(Attn);
  1317.             continue;
  1318.         case ZSKIP:
  1319. #ifdef SEGMENTS
  1320.             putsec(secbuf, chinseg);
  1321.             chinseg = 0;
  1322. #endif
  1323.             Modtime = 1;
  1324.             closeit();
  1325.             vfile("rzfile: Sender SKIPPED file");
  1326.             return c;
  1327.         case ZDATA:
  1328.             if (rclhdr(Rxhdr) != rxbytes) {
  1329.                 if ( --n < 0) {
  1330.                     return ERROR;
  1331.                 }
  1332. #ifdef SEGMENTS
  1333.                 putsec(secbuf, chinseg);
  1334.                 chinseg = 0;
  1335. #endif
  1336.                 zmputs(Attn);  continue;
  1337.             }
  1338. moredata:
  1339.             if (Verbose>1)
  1340.                 fprintf(stderr, "\r%7ld ZMODEM%s    ",
  1341.                   rxbytes, Crc32r?" CRC-32":"");
  1342. #ifdef SEGMENTS
  1343.             if (chinseg >= (1024 * SEGMENTS)) {
  1344.                 putsec(secbuf, chinseg);
  1345.                 chinseg = 0;
  1346.             }
  1347.             switch (c = zrdata(secbuf+chinseg, 1024))
  1348. #else
  1349.             switch (c = zrdata(secbuf, 1024))
  1350. #endif
  1351.             {
  1352.             case ZCAN:
  1353. #ifdef SEGMENTS
  1354.                 putsec(secbuf, chinseg);
  1355.                 chinseg = 0;
  1356. #endif
  1357.                 vfile("rzfile: zgethdr returned %d", c);
  1358.                 return ERROR;
  1359.             case ERROR:    /* CRC error */
  1360. #ifdef SEGMENTS
  1361.                 putsec(secbuf, chinseg);
  1362.                 chinseg = 0;
  1363. #endif
  1364.                 if ( --n < 0) {
  1365.                     vfile("rzfile: zgethdr returned %d", c);
  1366.                     return ERROR;
  1367.                 }
  1368.                 zmputs(Attn);
  1369.                 continue;
  1370.             case TIMEOUT:
  1371. #ifdef SEGMENTS
  1372.                 putsec(secbuf, chinseg);
  1373.                 chinseg = 0;
  1374. #endif
  1375.                 if ( --n < 0) {
  1376.                     vfile("rzfile: zgethdr returned %d", c);
  1377.                     return ERROR;
  1378.                 }
  1379.                 continue;
  1380.             case GOTCRCW:
  1381.                 n = 20;
  1382. #ifdef SEGMENTS
  1383.                 chinseg += Rxcount;
  1384.                 putsec(secbuf, chinseg);
  1385.                 chinseg = 0;
  1386. #else
  1387.                 putsec(secbuf, Rxcount);
  1388. #endif
  1389.                 rxbytes += Rxcount;
  1390.                 stohdr(rxbytes);
  1391.                 zshhdr(4,ZACK, Txhdr);
  1392.                 sendline(XON);
  1393.                 goto nxthdr;
  1394.             case GOTCRCQ:
  1395.                 n = 20;
  1396. #ifdef SEGMENTS
  1397.                 chinseg += Rxcount;
  1398. #else
  1399.                 putsec(secbuf, Rxcount);
  1400. #endif
  1401.                 rxbytes += Rxcount;
  1402.                 stohdr(rxbytes);
  1403.                 zshhdr(4,ZACK, Txhdr);
  1404.                 goto moredata;
  1405.             case GOTCRCG:
  1406.                 n = 20;
  1407. #ifdef SEGMENTS
  1408.                 chinseg += Rxcount;
  1409. #else
  1410.                 putsec(secbuf, Rxcount);
  1411. #endif
  1412.                 rxbytes += Rxcount;
  1413.                 goto moredata;
  1414.             case GOTCRCE:
  1415.                 n = 20;
  1416. #ifdef SEGMENTS
  1417.                 chinseg += Rxcount;
  1418. #else
  1419.                 putsec(secbuf, Rxcount);
  1420. #endif
  1421.                 rxbytes += Rxcount;
  1422.                 goto nxthdr;
  1423.             }
  1424.         }
  1425.     }
  1426. }
  1427.  
  1428. /*
  1429.  * Send a string to the modem, processing for \336 (sleep 1 sec)
  1430.  *   and \335 (break signal)
  1431.  */
  1432. zmputs(s)
  1433. char *s;
  1434. {
  1435.     register c;
  1436.  
  1437.     while (*s) {
  1438.         switch (c = *s++) {
  1439.         case '\336':
  1440.             sleep(1); continue;
  1441.         case '\335':
  1442.             sendbrk(); continue;
  1443.         default:
  1444.             sendline(c);
  1445.         }
  1446.     }
  1447. }
  1448.  
  1449. /*
  1450.  * Close the receive dataset, return OK or ERROR
  1451.  */
  1452. closeit()
  1453. {
  1454.     time_t time();
  1455.  
  1456. #ifndef vax11c
  1457.     if (Topipe) {
  1458.         if (pclose(fout)) {
  1459.             return ERROR;
  1460.         }
  1461.         return OK;
  1462.     }
  1463. #endif
  1464.     if (fclose(fout)==ERROR) {
  1465.         fprintf(stderr, "file close ERROR\n");
  1466.         return ERROR;
  1467.     }
  1468. #ifndef vax11c
  1469.     if (Modtime) {
  1470.         timep[0] = time(NULL);
  1471.         timep[1] = Modtime;
  1472.         utime(Pathname, timep);
  1473.     }
  1474. #endif
  1475.     if ((Filemode&S_IFMT) == S_IFREG)
  1476.         chmod(Pathname, (07777 & Filemode));
  1477.     return OK;
  1478. }
  1479.  
  1480. /*
  1481.  * Ack a ZFIN packet, let byegones be byegones
  1482.  */
  1483. ackbibi()
  1484. {
  1485.     register n;
  1486.  
  1487.     vfile("ackbibi:");
  1488.     Readnum = 1;
  1489.     stohdr(0L);
  1490.     for (n=3; --n>=0; ) {
  1491.         purgeline();
  1492.         zshhdr(4,ZFIN, Txhdr);
  1493.         switch (readline(100)) {
  1494.         case 'O':
  1495.             readline(1);    /* Discard 2nd 'O' */
  1496.             vfile("ackbibi complete");
  1497.             return;
  1498.         case RCDO:
  1499.             return;
  1500.         case TIMEOUT:
  1501.         default:
  1502.             break;
  1503.         }
  1504.     }
  1505. }
  1506.  
  1507.  
  1508.  
  1509. /*
  1510.  * Local console output simulation
  1511.  */
  1512. bttyout(c)
  1513. {
  1514.     if (Verbose || Fromcu)
  1515.         putc(c, stderr);
  1516. }
  1517.  
  1518. #ifndef vax11c
  1519. /*
  1520.  * Strip leading ! if present, do shell escape. 
  1521.  */
  1522. sys2(s)
  1523. register char *s;
  1524. {
  1525.     if (*s == '!')
  1526.         ++s;
  1527.     return system(s);
  1528. }
  1529. /*
  1530.  * Strip leading ! if present, do exec.
  1531.  */
  1532. exec2(s)
  1533. register char *s;
  1534. {
  1535.     if (*s == '!')
  1536.         ++s;
  1537.     mode(0);
  1538.     execl("/bin/sh", "sh", "-c", s);
  1539. }
  1540. #endif
  1541. /* End of rz.c */
  1542.